1 Context

In this exercise we are going to study the results from a particle analysis performed on a set of SEM images of Ni nanoparticles.

To obtain these nanoparticles, we start from Si wafers on which a 5 or 10 nm layer of Ni is deposited by PVD. These wafers are then heated in an H2 atmosphere to reduce them, which provokes the formation of nanoparticles through unwetting of the Si surface. These nanoparticles are then used as catalyst for the growth of vertically aligned carbon nanotubes by PECVD. As the diameter and density of the tubes are directly related to the diameter and density of the nanoparticles, we are interested in getting a clear idea of these parameters before performing the nanotube growth.

Some Ni-covered Si wafers were prepared before the first confinement (substrates labeled as old), some were prepared in September (new substrates). Here, we are interested in seeing whether the age and thickness of the Ni layer plays a role on the nanoparticles size and density. Also, the other parameters to study are the temperature at which the unwetting is performed, as well as the duration of this reaction.

To perform this study, we prepared samples from various substrates at various temperatures and during various times. The substrates are then observed with SEM, and several pictures are taken to increase the statistics. These pictures are then analyzed with ImageJ, as shown on Figure 1.1.

Typical SEM image of Ni nanoparticles: from the raw image to particle analysisTypical SEM image of Ni nanoparticles: from the raw image to particle analysisTypical SEM image of Ni nanoparticles: from the raw image to particle analysis

Figure 1.1: Typical SEM image of Ni nanoparticles: from the raw image to particle analysis

In this exercise, we are going to treat the tables obtained from ImageJ: these tables contain the (x,y) positions of the particles as well as their area.

2 Data wrangling

  • Load the packages tidyverse, readxl, units, broom, and ggforce. We are going to getting used to work with units in this exercise, which is a very good habit to take in order to avoid many unit conversion problems. The package ggforce allows doing ggplot plots with tibbles containing units. Set the global ggplot2 theme to black and white. Also, make it so that the strip.background (background of the facets titles) is blank, and that the strip.text is bold.
  • Find all MLxx_xx_cc.csv files in the Data folder and store them in flist.
  • Read the sample.xlsx file that contain all characteristics of the various samples, such as their temperature, substrate type, time of reaction, and store the result in samples.
    • Modify the tibble samples so that its columns are named “sample”, “T”, “time”, and “substrate”
    • Using separate(), separate the “substrate” column into “sub_thick” and “sub_age” containing the thickness and age of the substrate. Use convert = TRUE to convert the characters to integers if applicable.
    • Give the columns their proper unit when applicable (refer to this example)
  • Create the readfile(filename) function that, given one of the csv files names, will:
    • Determine the unit used in this file: from filename, store the unit into the variable UNIT (that should be the string "um" or "nm"). You can use unlist(strsplit(filename,"_")) to get a vector of the elements of filename separated by a _ character.
    • Read the csv file, then successively:
    • Select only the X, Y and Area columns (some files have more columns) and rename them to lowercases names.
    • Add the file column containing the filename, and then separate it into 3 columns sample, number and unit
    • Remove the unit column
    • Apply the corresponding units to x, y and area. You can apply a unit to a vector x based on a string xx using set_units(x, xx, mode = "standard").
    • Create a column diameter containing the diameter of the particles.
  • Test this function on 2 files with 2 different units to check that it gives the expected result.
## # A tibble: 100 x 6
##        x     y   area sample number   diameter
##     [um]  [um] [um^2] <chr>  <chr>        [um]
##  1 0.221 0.116  0.006 ML16   02     0.08740387
##  2 0.328 0.273  0.009 ML16   02     0.10704745
##  3 0.497 0.423  0.007 ML16   02     0.09440697
##  4 0.189 0.638  0.011 ML16   02     0.11834541
##  5 0.421 1.067  0.010 ML16   02     0.11283792
##  6 0.222 1.410  0.007 ML16   02     0.09440697
##  7 0.634 1.438  0.011 ML16   02     0.11834541
##  8 0.634 1.438  0.011 ML16   02     0.11834541
##  9 0.408 1.576  0.009 ML16   02     0.10704745
## 10 1.677 0.294  0.009 ML16   02     0.10704745
## # … with 90 more rows
## # A tibble: 95 x 6
##          x        y      area sample number  diameter
##       [nm]     [nm]    [nm^2] <chr>  <chr>       [nm]
##  1 485.145  176.363  8177.769 ML16   04     102.04048
##  2 552.574  421.864  9433.278 ML16   04     109.59390
##  3 907.114   82.537 14149.916 ML16   04     134.22456
##  4 781.287  193.600  5123.831 ML16   04      80.77044
##  5 762.260  447.889  9433.278 ML16   04     109.59390
##  6 521.046  927.668 16118.010 ML16   04     143.25532
##  7 781.635  653.703  8008.106 ML16   04     100.97642
##  8 906.002 1081.880  9501.143 ML16   04     109.98741
##  9 869.637 1270.324  8381.365 ML16   04     103.30288
## 10 162.661 1767.427 10010.133 ML16   04     112.89507
## # … with 85 more rows
  • Using readfile() that you just defined, read all csv files and store them into a tidy tibble called particles. Do not use a for loop to do so. Join this table with the samples one. You will see that, since we attributed units to some columns, all data are automatically converted to a single unit. Filter the data for diameters lower than 40 µm as some very large particles were detected in the image processing that are actually not particles.

In case you didn’t manage to get there, here is the particles tibble (it doesn’t contain the units though as you can’t save it in a text file.)

3 Plotting and analysis

3.1 Size analysis

  • Now, plot the histogram of all particle diameters, with a fill color depending on the time (you need to convert time to a factor), and with a grid showing temperature vs. substrate age and thickness. Put the legend on top of the graph, and add some transparency to your colors.
  • In fact, I usually prefer to plot it using geom_density() which is basically an histogram convoluted with a Gaussian distribution of bandwidth bw. This allows for smoother graphs. Make this plot and play with the bw parameter.
  • Convert – with ggplot – the unit of the particle diameters to nanometers or any other unit you want.

  • Now, store in particles_ave the average particle diameter and its standard deviation per substrate thickness and age, time and temperature of reaction. You will note that mean() keeps the unit of vectors while sd() loses it. Make sure that the standard deviation column has the proper unit (use units(a) <- units(b)).
  • Plot the average diameter evolution with reaction time, with a color per substrate thickness, and on a grid showing substrate age vs temperature.
    • Don’t forget to add error bars corresponding to the standard error of the diameters distribution.
    • Add a line showing a linear fit for all groups.
    • Make sure both plot axes go to 0.
    • Put the legend on top.
    • Define nice axis labels (with sentences instead of column names). In case a column has a unit that was attributed, it will return an error in case the axis label you want to give contains white spaces. You will thus need to use backticks, like so: "`Two words`"

  • Using broom display the slopes and intercept of all linear fits, without using a for loop. This doesn’t work well with units, so prior to doing the fit, remove the units of your time and diameter columns using as.vector().
## # A tibble: 6 x 7
## # Groups:   sub_thick, sub_age [3]
##   sub_thick sub_age     t    y0    dy0  slope  dslope
##        [nm] <chr>    [°C] <dbl>  <dbl>  <dbl>   <dbl>
## 1         5 new       750  80.5   4.36 -1.31    0.270
## 2         5 new       850  96.2 NaN    -1.48  NaN    
## 3         5 old       750 191.   14.1  -5.80    0.878
## 4         5 old       850  92.8 NaN    -0.210 NaN    
## 5        10 old       750 198.   12.4  -3.56    0.775
## 6        10 old       850 159.  NaN    -2.35  NaN

3.2 Density and ordering analysis

  • Now we want to see the evolution of the density of particles and their ordering. One way of doing this is to look at the G(r) distribution, i.e. the probability to find a particle in r if one is in 0. I provide here below the function gofr(x,y,dr,Rmax) that computes it between 0 and Rmax with a step dr, provided the (x,y) positions of particles.
  • Using pipe operations, compute G(r) for each image and store it into particles_gofr.
    • We want to compute G(r) up to 500 nm by step of 2 nm. Make sure x, y, dr and Rmax are given with the same unit.
    • Then, compute the average G(r) for each sample.
    • Join particles_gofr with samples to retrieve the samples information
  • Find the best way to represent G(r) for all samples, that allows seeing the evolution with all parameters.

LS0tCnRpdGxlIDogIlIgRXhlcmNpc2VzIC0gUGFydGljbGUgYW5hbHlzaXMgZnJvbSBTRU0gaW1hZ2VzIgpkYXRlICA6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OiAKICAgIGJvb2tkb3duOjpodG1sX2RvY3VtZW50MjoKICAgICAgICB0b2MgICAgICAgICAgICA6IFRSVUUKICAgICAgICB0b2NfZmxvYXQgICAgICA6IFRSVUUKICAgICAgICB0b2NfZGVwdGggICAgICA6IDQKICAgICAgICBoaWdobGlnaHQgICAgICA6IHRhbmdvCiAgICAgICAgbnVtYmVyX3NlY3Rpb25zOiBUUlVFCiAgICAgICAgY29kZV9kb3dubG9hZCAgOiBUUlVFCiAgICAgICAgY29kZV9mb2xkaW5nICAgOiBoaWRlCnBhcmFtczogCiAgICBzb2x1dGlvbjoKICAgICAgICB2YWx1ZTogVFJVRQotLS0KCgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgpibG9ja3F1b3RlIHsKICBiYWNrZ3JvdW5kOiAjRTlGOUZGOwogIGJvcmRlci1sZWZ0OiA1cHggc29saWQgIzAyNjA4NjsKICBtYXJnaW46IDEuNWVtIDEwcHg7CiAgcGFkZGluZzogMC41ZW0gMTBweDsKICBmb250LXNpemU6IDFlbTsKfQo8L3N0eWxlPgoKIyBDb250ZXh0CgpJbiB0aGlzIGV4ZXJjaXNlIHdlIGFyZSBnb2luZyB0byBzdHVkeSB0aGUgcmVzdWx0cyBmcm9tIGEgcGFydGljbGUgYW5hbHlzaXMgcGVyZm9ybWVkIG9uIGEgc2V0IG9mIFNFTSBpbWFnZXMgb2YgTmkgbmFub3BhcnRpY2xlcy4gCgpUbyBvYnRhaW4gdGhlc2UgbmFub3BhcnRpY2xlcywgd2Ugc3RhcnQgZnJvbSBTaSB3YWZlcnMgb24gd2hpY2ggYSA1IG9yIDEwIG5tIGxheWVyIG9mIE5pIGlzIGRlcG9zaXRlZCBieSBQVkQuIFRoZXNlIHdhZmVycyBhcmUgdGhlbiBoZWF0ZWQgaW4gYW4gSH4yfiBhdG1vc3BoZXJlIHRvIHJlZHVjZSB0aGVtLCB3aGljaCBwcm92b2tlcyB0aGUgZm9ybWF0aW9uIG9mIG5hbm9wYXJ0aWNsZXMgdGhyb3VnaCB1bndldHRpbmcgb2YgdGhlIFNpIHN1cmZhY2UuIFRoZXNlIG5hbm9wYXJ0aWNsZXMgYXJlIHRoZW4gdXNlZCBhcyBjYXRhbHlzdCBmb3IgdGhlIGdyb3d0aCBvZiB2ZXJ0aWNhbGx5IGFsaWduZWQgY2FyYm9uIG5hbm90dWJlcyBieSBQRUNWRC4gQXMgdGhlIGRpYW1ldGVyIGFuZCBkZW5zaXR5IG9mIHRoZSB0dWJlcyBhcmUgZGlyZWN0bHkgcmVsYXRlZCB0byB0aGUgZGlhbWV0ZXIgYW5kIGRlbnNpdHkgb2YgdGhlIG5hbm9wYXJ0aWNsZXMsIHdlIGFyZSBpbnRlcmVzdGVkIGluIGdldHRpbmcgYSBjbGVhciBpZGVhIG9mIHRoZXNlIHBhcmFtZXRlcnMgYmVmb3JlIHBlcmZvcm1pbmcgdGhlIG5hbm90dWJlIGdyb3d0aC4KClNvbWUgTmktY292ZXJlZCBTaSB3YWZlcnMgd2VyZSBwcmVwYXJlZCBiZWZvcmUgdGhlIGZpcnN0IGNvbmZpbmVtZW50IChzdWJzdHJhdGVzIGxhYmVsZWQgYXMgYG9sZGApLCBzb21lIHdlcmUgcHJlcGFyZWQgaW4gU2VwdGVtYmVyIChgbmV3YCBzdWJzdHJhdGVzKS4gSGVyZSwgd2UgYXJlIGludGVyZXN0ZWQgaW4gc2VlaW5nIHdoZXRoZXIgdGhlIGFnZSBhbmQgdGhpY2tuZXNzIG9mIHRoZSBOaSBsYXllciBwbGF5cyBhIHJvbGUgb24gdGhlIG5hbm9wYXJ0aWNsZXMgc2l6ZSBhbmQgZGVuc2l0eS4gQWxzbywgdGhlIG90aGVyIHBhcmFtZXRlcnMgdG8gc3R1ZHkgYXJlIHRoZSB0ZW1wZXJhdHVyZSBhdCB3aGljaCB0aGUgdW53ZXR0aW5nIGlzIHBlcmZvcm1lZCwgYXMgd2VsbCBhcyB0aGUgZHVyYXRpb24gb2YgdGhpcyByZWFjdGlvbi4KClRvIHBlcmZvcm0gdGhpcyBzdHVkeSwgd2UgcHJlcGFyZWQgc2FtcGxlcyBmcm9tIHZhcmlvdXMgc3Vic3RyYXRlcyBhdCB2YXJpb3VzIHRlbXBlcmF0dXJlcyBhbmQgZHVyaW5nIHZhcmlvdXMgdGltZXMuIFRoZSBzdWJzdHJhdGVzIGFyZSB0aGVuIG9ic2VydmVkIHdpdGggU0VNLCBhbmQgc2V2ZXJhbCBwaWN0dXJlcyBhcmUgdGFrZW4gdG8gaW5jcmVhc2UgdGhlIHN0YXRpc3RpY3MuIFRoZXNlIHBpY3R1cmVzIGFyZSB0aGVuIGFuYWx5emVkIHdpdGggW0ltYWdlSl0oaHR0cHM6Ly9pbWFnZWoubmV0L1dlbGNvbWUpLCBhcyBzaG93biBvbiBGaWd1cmUgXEByZWYoZmlnOlNFTWltYWdlcykuIAoKYGBge3IgU0VNaW1hZ2VzLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuY2FwPSJUeXBpY2FsIFNFTSBpbWFnZSBvZiBOaSBuYW5vcGFydGljbGVzOiBmcm9tIHRoZSByYXcgaW1hZ2UgdG8gcGFydGljbGUgYW5hbHlzaXMiLCBmaWcuYWxpZ249ImNlbnRlciIsIG91dC53aWR0aD0iMzMlIiwgZmlnLnNob3c9J2hvbGQnfQpteWltYWdlcyA8LSBjKCJEYXRhL01MMjZfMDEucG5nIiwgIkRhdGEvTUwyNl8wMS10aHJlc2hvbGQucG5nIiwgIkRhdGEvTUwyNl8wMS1wYXJ0aWNsZXMucG5nIikKa25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MobXlpbWFnZXMpCmBgYAoKSW4gdGhpcyBleGVyY2lzZSwgd2UgYXJlIGdvaW5nIHRvIHRyZWF0IHRoZSB0YWJsZXMgb2J0YWluZWQgZnJvbSBJbWFnZUo6IHRoZXNlIHRhYmxlcyBjb250YWluIHRoZSAoeCx5KSBwb3NpdGlvbnMgb2YgdGhlIHBhcnRpY2xlcyBhcyB3ZWxsIGFzIHRoZWlyIGFyZWEuCgojIERhdGEgd3JhbmdsaW5nCgotIExvYWQgdGhlIHBhY2thZ2VzIGB0aWR5dmVyc2VgLCBgcmVhZHhsYCwgYHVuaXRzYCwgYGJyb29tYCwgYW5kIGBnZ2ZvcmNlYC4gV2UgYXJlIGdvaW5nIHRvIGdldHRpbmcgdXNlZCB0byB3b3JrIHdpdGggdW5pdHMgaW4gdGhpcyBleGVyY2lzZSwgd2hpY2ggaXMgYSB2ZXJ5IGdvb2QgaGFiaXQgdG8gdGFrZSBpbiBvcmRlciB0byBhdm9pZCBtYW55IHVuaXQgY29udmVyc2lvbiBwcm9ibGVtcy4gVGhlIHBhY2thZ2UgYGdnZm9yY2VgIGFsbG93cyBkb2luZyBgZ2dwbG90YCBwbG90cyB3aXRoIHRpYmJsZXMgY29udGFpbmluZyB1bml0cy4gU2V0IHRoZSBnbG9iYWwgYGdncGxvdDJgIHRoZW1lIHRvIGJsYWNrIGFuZCB3aGl0ZS4gQWxzbywgbWFrZSBpdCBzbyB0aGF0IHRoZSBgc3RyaXAuYmFja2dyb3VuZGAgKGJhY2tncm91bmQgb2YgdGhlIGZhY2V0cyB0aXRsZXMpIGlzIGJsYW5rLCBhbmQgdGhhdCB0aGUgYHN0cmlwLnRleHRgIGlzIGJvbGQuCgpgYGB7ciBpbmNsdWRlPXBhcmFtcyRzb2x1dGlvbiwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShyZWFkeGwpCmxpYnJhcnkodW5pdHMpCmxpYnJhcnkoZ2dmb3JjZSkKbGlicmFyeShicm9vbSkKdGhlbWVfc2V0KHRoZW1lX2J3KCkrCiAgICAgICAgICB0aGVtZShzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgc3RyaXAudGV4dD1lbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZT0xNCkKICAgICAgICAgICAgICAgICkpCmBgYAoKLSBGaW5kIGFsbCBNTHh4X3h4X2NjLmNzdiBmaWxlcyBpbiB0aGUgYERhdGFgIGZvbGRlciBhbmQgc3RvcmUgdGhlbSBpbiBgZmxpc3RgLgoKYGBge3IgaW5jbHVkZT1wYXJhbXMkc29sdXRpb24sIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZT1GQUxTRX0KZmxpc3QgPC0gbGlzdC5maWxlcyhwYXRoPSJEYXRhIiwgcGF0dGVybj0ibS5jc3YiKQpgYGAKCi0gUmVhZCB0aGUgYHNhbXBsZS54bHN4YCBmaWxlIHRoYXQgY29udGFpbiBhbGwgY2hhcmFjdGVyaXN0aWNzIG9mIHRoZSB2YXJpb3VzIHNhbXBsZXMsIHN1Y2ggYXMgdGhlaXIgdGVtcGVyYXR1cmUsIHN1YnN0cmF0ZSB0eXBlLCB0aW1lIG9mIHJlYWN0aW9uLCBhbmQgc3RvcmUgdGhlIHJlc3VsdCBpbiBgc2FtcGxlc2AuIAogICAgLSBNb2RpZnkgdGhlIHRpYmJsZSBgc2FtcGxlc2Agc28gdGhhdCBpdHMgY29sdW1ucyBhcmUgbmFtZWQgInNhbXBsZSIsICJUIiwgInRpbWUiLCBhbmQgInN1YnN0cmF0ZSIKICAgIC0gVXNpbmcgYHNlcGFyYXRlKClgey5SfSwgc2VwYXJhdGUgdGhlICJzdWJzdHJhdGUiIGNvbHVtbiBpbnRvICJzdWJfdGhpY2siIGFuZCAic3ViX2FnZSIgY29udGFpbmluZyB0aGUgdGhpY2tuZXNzIGFuZCBhZ2Ugb2YgdGhlIHN1YnN0cmF0ZS4gVXNlIGBjb252ZXJ0ID0gVFJVRWAgdG8gY29udmVydCB0aGUgY2hhcmFjdGVycyB0byBpbnRlZ2VycyBpZiBhcHBsaWNhYmxlLgogICAgLSBHaXZlIHRoZSBjb2x1bW5zIHRoZWlyIHByb3BlciB1bml0IHdoZW4gYXBwbGljYWJsZSAocmVmZXIgdG8gW3RoaXMgZXhhbXBsZV0oaHR0cHM6Ly9sbWkuY25ycy5mci9yL3dvcmtpbmctd2l0aC11bml0cy5odG1sKSkKCmBgYHtyIGluY2x1ZGU9cGFyYW1zJHNvbHV0aW9uLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9CnNhbXBsZXMgPC0gcmVhZF9leGNlbCgiRGF0YS9zYW1wbGUueGxzeCIpICU+JSAKICAgIHJlbmFtZShzYW1wbGUgICAgPSAibmFtZSIsCiAgICAgICAgICAgVCAgICAgICAgID0gIlRlbXBlcmF0dXJlICjCsEMpIiwKICAgICAgICAgICB0aW1lICAgICAgPSAiVGltZSAobWludXRlcykiLAogICAgICAgICAgIHN1YnN0cmF0ZSA9ICJTdWJzdHJhdGUgKG5tKSIpICU+JSAKICAgIHNlcGFyYXRlKHN1YnN0cmF0ZSwgYygic3ViX3RoaWNrIiwic3ViX2FnZSIpLCBjb252ZXJ0ID0gVFJVRSkgJT4lIAogICAgbXV0YXRlKHN1Yl90aGljayA9IHNldF91bml0cyhzdWJfdGhpY2ssIm5tIiksCiAgICAgICAgICAgdGltZSAgICAgID0gc2V0X3VuaXRzKHRpbWUsIm1pbiIpLAogICAgICAgICAgIFQgICAgICAgICA9IHNldF91bml0cyhULCJkZWdDIikKICAgICAgICAgICApCmBgYAoKLSBDcmVhdGUgdGhlIGByZWFkZmlsZShmaWxlbmFtZSlgey5SfSBmdW5jdGlvbiB0aGF0LCBnaXZlbiBvbmUgb2YgdGhlIGNzdiBmaWxlcyBuYW1lcywgd2lsbDoKICAgIC0gRGV0ZXJtaW5lIHRoZSB1bml0IHVzZWQgaW4gdGhpcyBmaWxlOiBmcm9tIGBmaWxlbmFtZWAsIHN0b3JlIHRoZSB1bml0IGludG8gdGhlIHZhcmlhYmxlIGBVTklUYCAodGhhdCBzaG91bGQgYmUgdGhlIHN0cmluZyBgInVtImAgb3IgYCJubSJgKS4gWW91IGNhbiB1c2UgYHVubGlzdChzdHJzcGxpdChmaWxlbmFtZSwiXyIpKWB7LlJ9IHRvIGdldCBhIHZlY3RvciBvZiB0aGUgZWxlbWVudHMgb2YgYGZpbGVuYW1lYCBzZXBhcmF0ZWQgYnkgYSBgX2AgY2hhcmFjdGVyLgogICAgLSBSZWFkIHRoZSBjc3YgZmlsZSwgdGhlbiBzdWNjZXNzaXZlbHk6CiAgICAtIFNlbGVjdCBvbmx5IHRoZSBYLCBZIGFuZCBBcmVhIGNvbHVtbnMgKHNvbWUgZmlsZXMgaGF2ZSBtb3JlIGNvbHVtbnMpIGFuZCByZW5hbWUgdGhlbSB0byBsb3dlcmNhc2VzIG5hbWVzLgogICAgLSBBZGQgdGhlIGBmaWxlYCBjb2x1bW4gY29udGFpbmluZyB0aGUgZmlsZW5hbWUsIGFuZCB0aGVuIHNlcGFyYXRlIGl0IGludG8gMyBjb2x1bW5zIGBzYW1wbGVgLCBgbnVtYmVyYCBhbmQgYHVuaXRgCiAgICAtIFJlbW92ZSB0aGUgYHVuaXRgIGNvbHVtbgogICAgLSBBcHBseSB0aGUgY29ycmVzcG9uZGluZyB1bml0cyB0byB4LCB5IGFuZCBhcmVhLiBZb3UgY2FuIGFwcGx5IGEgdW5pdCB0byBhIHZlY3RvciBgeGAgYmFzZWQgb24gYSAqKnN0cmluZyoqIGB4eGAgdXNpbmcgYHNldF91bml0cyh4LCB4eCwgbW9kZSA9ICJzdGFuZGFyZCIpYHsuUn0uCiAgICAtIENyZWF0ZSBhIGNvbHVtbiBgZGlhbWV0ZXJgIGNvbnRhaW5pbmcgdGhlIGRpYW1ldGVyIG9mIHRoZSBwYXJ0aWNsZXMuCi0gVGVzdCB0aGlzIGZ1bmN0aW9uIG9uIDIgZmlsZXMgd2l0aCAyIGRpZmZlcmVudCB1bml0cyB0byBjaGVjayB0aGF0IGl0IGdpdmVzIHRoZSBleHBlY3RlZCByZXN1bHQuCgpgYGB7ciBpbmNsdWRlPXBhcmFtcyRzb2x1dGlvbiwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFfQpyZWFkZmlsZSA8LSBmdW5jdGlvbihmaWxlbmFtZSl7CiAgICBVTklUIDwtIHVubGlzdChzdHJzcGxpdChmaWxlbmFtZSwiXyIpKQogICAgVU5JVCA8LSBnc3ViKCIuY3N2IiwiIixVTklUW2xlbmd0aChVTklUKV0pCiAgICByZWFkX2NzdihmaWxlbmFtZSkgJT4lIAogICAgICAgIHJlbmFtZV9hbGwodG9sb3dlcikgJT4lIAogICAgICAgIHNlbGVjdCh4LHksYXJlYSkgJT4lIAogICAgICAgIG11dGF0ZShmaWxlPWdzdWIoIkRhdGEvIiwiIixmaWxlbmFtZSkpICU+JSAKICAgICAgICBzZXBhcmF0ZShmaWxlLCBjKCJzYW1wbGUiLCJudW1iZXIiLCJ1bml0IiksIHNlcD0iXyIpICU+JSAKICAgICAgICBzZWxlY3QoLXVuaXQpICU+JSAKICAgICAgICBtdXRhdGUoeCAgICAgICAgPSBzZXRfdW5pdHMoeCwgVU5JVCwgbW9kZSA9ICJzdGFuZGFyZCIpLAogICAgICAgICAgICAgICB5ICAgICAgICA9IHNldF91bml0cyh5LCBVTklULCBtb2RlID0gInN0YW5kYXJkIiksCiAgICAgICAgICAgICAgIGFyZWEgICAgID0gc2V0X3VuaXRzKGFyZWEsIHBhc3RlMChVTklULCIqIixVTklUKSwgbW9kZSA9ICJzdGFuZGFyZCIpLAogICAgICAgICAgICAgICBkaWFtZXRlciA9IHNxcnQoNCphcmVhL3BpKSkKfQpyZWFkZmlsZSgiRGF0YS9NTDE2XzAyX3VtLmNzdiIpCnJlYWRmaWxlKCJEYXRhL01MMTZfMDRfbm0uY3N2IikKYGBgCgotIFVzaW5nIGByZWFkZmlsZSgpYHsuUn0gdGhhdCB5b3UganVzdCBkZWZpbmVkLCByZWFkIGFsbCBjc3YgZmlsZXMgYW5kIHN0b3JlIHRoZW0gaW50byBhIHRpZHkgdGliYmxlIGNhbGxlZCBgcGFydGljbGVzYC4gKipEbyBub3QgdXNlIGEgZm9yIGxvb3AgdG8gZG8gc28uKiogSm9pbiB0aGlzIHRhYmxlIHdpdGggdGhlIGBzYW1wbGVzYCBvbmUuIFlvdSB3aWxsIHNlZSB0aGF0LCBzaW5jZSB3ZSBhdHRyaWJ1dGVkIHVuaXRzIHRvIHNvbWUgY29sdW1ucywgYWxsIGRhdGEgYXJlIGF1dG9tYXRpY2FsbHkgY29udmVydGVkIHRvIGEgc2luZ2xlIHVuaXQuIEZpbHRlciB0aGUgZGF0YSBmb3IgZGlhbWV0ZXJzIGxvd2VyIHRoYW4gNDAgwrVtIGFzIHNvbWUgdmVyeSBsYXJnZSBwYXJ0aWNsZXMgd2VyZSBkZXRlY3RlZCBpbiB0aGUgaW1hZ2UgcHJvY2Vzc2luZyB0aGF0IGFyZSBhY3R1YWxseSBub3QgcGFydGljbGVzLgoKYGBge3IgaW5jbHVkZT1wYXJhbXMkc29sdXRpb24sIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZT1GQUxTRX0KcGFydGljbGVzIDwtIHRpYmJsZShmaWxlPWZsaXN0KSAlPiUgCiAgICBtdXRhdGUoZGF0YSA9IG1hcChmaWxlLCB+cmVhZGZpbGUoZmlsZS5wYXRoKCJEYXRhIiwuKSkpKSAlPiUgCiAgICB1bm5lc3QoZGF0YSkgJT4lIAogICAgaW5uZXJfam9pbihzYW1wbGVzKSAlPiUgCiAgICBmaWx0ZXIoZGlhbWV0ZXI8c2V0X3VuaXRzKDQwLCJ1bSIpKQpgYGAKCmBgYHtyIGluY2x1ZGU9RkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZT1GQUxTRX0Kd3JpdGVfdHN2KHBhcnRpY2xlcywgIkRhdGEvcGFydGljbGVzLmRhdCIpCmBgYAoKPiBJbiBjYXNlIHlvdSBkaWRuJ3QgbWFuYWdlIHRvIGdldCB0aGVyZSwgW2hlcmVdKERhdGEvcGFydGljbGVzLmRhdCkgaXMgdGhlIGBwYXJ0aWNsZXNgIHRpYmJsZSAoaXQgZG9lc24ndCBjb250YWluIHRoZSB1bml0cyB0aG91Z2ggYXMgeW91IGNhbid0IHNhdmUgaXQgaW4gYSB0ZXh0IGZpbGUuKQoKCiMgUGxvdHRpbmcgYW5kIGFuYWx5c2lzCgojIyBTaXplIGFuYWx5c2lzCgotIE5vdywgcGxvdCB0aGUgaGlzdG9ncmFtIG9mIGFsbCBwYXJ0aWNsZSBkaWFtZXRlcnMsIHdpdGggYSBmaWxsIGNvbG9yIGRlcGVuZGluZyBvbiB0aGUgdGltZSAoeW91IG5lZWQgdG8gY29udmVydCB0aW1lIHRvIGEgZmFjdG9yKSwgYW5kIHdpdGggYSBncmlkIHNob3dpbmcgdGVtcGVyYXR1cmUgdnMuIHN1YnN0cmF0ZSBhZ2UgYW5kIHRoaWNrbmVzcy4gUHV0IHRoZSBsZWdlbmQgb24gdG9wIG9mIHRoZSBncmFwaCwgYW5kIGFkZCBzb21lIHRyYW5zcGFyZW5jeSB0byB5b3VyIGNvbG9ycy4KLSBJbiBmYWN0LCBJIHVzdWFsbHkgcHJlZmVyIHRvIHBsb3QgaXQgdXNpbmcgYGdlb21fZGVuc2l0eSgpYHsuUn0gd2hpY2ggaXMgYmFzaWNhbGx5IGFuIGhpc3RvZ3JhbSBjb252b2x1dGVkIHdpdGggYSBHYXVzc2lhbiBkaXN0cmlidXRpb24gb2YgYmFuZHdpZHRoIGBid2AuIFRoaXMgYWxsb3dzIGZvciBzbW9vdGhlciBncmFwaHMuIE1ha2UgdGhpcyBwbG90IGFuZCBwbGF5IHdpdGggdGhlIGBid2AgcGFyYW1ldGVyLgotIENvbnZlcnQgLS0gKndpdGggZ2dwbG90KiAtLSB0aGUgdW5pdCBvZiB0aGUgcGFydGljbGUgZGlhbWV0ZXJzIHRvIG5hbm9tZXRlcnMgb3IgYW55IG90aGVyIHVuaXQgeW91IHdhbnQuCgpgYGB7ciBpbmNsdWRlPXBhcmFtcyRzb2x1dGlvbiwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFfQpwYXJ0aWNsZXMgJT4lIAogICAgZ2dwbG90KGFlcyh4PWRpYW1ldGVyLCBmaWxsPWZhY3Rvcih0aW1lKSkpKwogICAgICAgIGdlb21fZGVuc2l0eShhbHBoYT0uNSwgY29sb3I9TkEsIGJ3PTQpKwogICAgICAgIGxhYnMoeCAgICA9ICJgUGFydGljbGUgRGlhbWV0ZXJgIiwKICAgICAgICAgICAgIHkgICAgPSAiRGVuc2l0eSBbYXJiLiB1bml0c10iLAogICAgICAgICAgICAgZmlsbCA9ICJUaW1lIFttaW5dIikrCiAgICAgICAgZmFjZXRfZ3JpZChyZW9yZGVyKHBhc3RlKFQsIksiKSxUKX4KICAgICAgICAgICAgICAgICAgIHJlb3JkZXIocGFzdGUoc3ViX3RoaWNrLCJubSBOaSAtIixzdWJfYWdlKSxzdWJfdGhpY2spLCAKICAgICAgICAgICAgICAgICAgIHNjYWxlcz0iZnJlZV95IikrCiAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpKwogICAgICAgIHNjYWxlX3hfdW5pdCh1bml0PSJubSIsIGxpbWl0cz1jKDAsMzAwKSkKYGBgCgotIE5vdywgc3RvcmUgaW4gYHBhcnRpY2xlc19hdmVgIHRoZSBhdmVyYWdlIHBhcnRpY2xlIGRpYW1ldGVyIGFuZCBpdHMgc3RhbmRhcmQgZGV2aWF0aW9uIHBlciBzdWJzdHJhdGUgdGhpY2tuZXNzIGFuZCBhZ2UsIHRpbWUgYW5kIHRlbXBlcmF0dXJlIG9mIHJlYWN0aW9uLiBZb3Ugd2lsbCBub3RlIHRoYXQgYG1lYW4oKWB7LlJ9IGtlZXBzIHRoZSB1bml0IG9mIHZlY3RvcnMgd2hpbGUgYHNkKClgey5SfSBsb3NlcyBpdC4gTWFrZSBzdXJlIHRoYXQgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBjb2x1bW4gaGFzIHRoZSBwcm9wZXIgdW5pdCAodXNlIGB1bml0cyhhKSA8LSB1bml0cyhiKWB7LlJ9KS4KCmBgYHtyIGluY2x1ZGU9cGFyYW1zJHNvbHV0aW9uLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9CnBhcnRpY2xlc19hdmUgPC0gcGFydGljbGVzICU+JSAKICAgIGdyb3VwX2J5KHN1Yl90aGljaywgc3ViX2FnZSwgdGltZSwgVCkgJT4lIAogICAgc3VtbWFyaXNlKGRpYW0gICA9IG1lYW4oZGlhbWV0ZXIpLAogICAgICAgICAgICAgIHNkZGlhbSA9IHNkKGRpYW1ldGVyKSkKdW5pdHMocGFydGljbGVzX2F2ZSRzZGRpYW0pIDwtIHVuaXRzKHBhcnRpY2xlc19hdmUkZGlhbSkKYGBgCgotIFBsb3QgdGhlIGF2ZXJhZ2UgZGlhbWV0ZXIgZXZvbHV0aW9uIHdpdGggcmVhY3Rpb24gdGltZSwgd2l0aCBhIGNvbG9yIHBlciBzdWJzdHJhdGUgdGhpY2tuZXNzLCBhbmQgb24gYSBncmlkIHNob3dpbmcgc3Vic3RyYXRlIGFnZSB2cyB0ZW1wZXJhdHVyZS4KICAgIC0gRG9uJ3QgZm9yZ2V0IHRvIGFkZCBlcnJvciBiYXJzIGNvcnJlc3BvbmRpbmcgdG8gdGhlIHN0YW5kYXJkIGVycm9yIG9mIHRoZSBkaWFtZXRlcnMgZGlzdHJpYnV0aW9uLgogICAgLSBBZGQgYSBsaW5lIHNob3dpbmcgYSBsaW5lYXIgZml0IGZvciBhbGwgZ3JvdXBzLiAKICAgIC0gTWFrZSBzdXJlIGJvdGggcGxvdCBheGVzIGdvIHRvIDAuIAogICAgLSBQdXQgdGhlIGxlZ2VuZCBvbiB0b3AuCiAgICAtIERlZmluZSBuaWNlIGF4aXMgbGFiZWxzICh3aXRoIHNlbnRlbmNlcyBpbnN0ZWFkIG9mIGNvbHVtbiBuYW1lcykuIEluIGNhc2UgYSBjb2x1bW4gaGFzIGEgdW5pdCB0aGF0IHdhcyBhdHRyaWJ1dGVkLCBpdCB3aWxsIHJldHVybiBhbiBlcnJvciBpbiBjYXNlIHRoZSBheGlzIGxhYmVsIHlvdSB3YW50IHRvIGdpdmUgY29udGFpbnMgd2hpdGUgc3BhY2VzLiBZb3Ugd2lsbCB0aHVzIG5lZWQgdG8gdXNlIGJhY2t0aWNrcywgbGlrZSBzbzogYGAiYFR3byB3b3Jkc2AiYGAKCmBgYHtyIGluY2x1ZGU9cGFyYW1zJHNvbHV0aW9uLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9CnBhcnRpY2xlc19hdmUgJT4lIAogICAgZ2dwbG90KGFlcyh4PXRpbWUsIHk9ZGlhbSwgY29sb3I9ZmFjdG9yKHN1Yl90aGljaykpKSsKICAgICAgICBnZW9tX3BvaW50KGFscGhhPS41KSsKICAgICAgICBleHBhbmRfbGltaXRzKHggPSAwLCB5PTApKwogICAgICAgIGdlb21fZXJyb3JiYXIoYWVzKHltaW49ZGlhbS1zZGRpYW0seW1heD1kaWFtK3NkZGlhbSksIHdpZHRoPS4yKSsKICAgICAgICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIiwgc2U9RkFMU0UsICkrCiAgICAgICAgZmFjZXRfZ3JpZChUfnN1Yl9hZ2UpKwogICAgICAgIGxhYnMoeCAgICAgPSAiVGltZSIsCiAgICAgICAgICAgICB5ICAgICA9ICJgQXZlcmFnZSBwYXJ0aWNsZSBkaWFtZXRlcmAiLAogICAgICAgICAgICAgY29sb3IgPSAiU3Vic3RyYXRlIHRoaWNrbmVzcyBbbm1dIikrCiAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpKwogICAgICAgIHNjYWxlX3lfdW5pdCh1bml0PSJubSIpCmBgYAoKLSBVc2luZyBgYnJvb21gIGRpc3BsYXkgdGhlIHNsb3BlcyBhbmQgaW50ZXJjZXB0IG9mIGFsbCBsaW5lYXIgZml0cywgKip3aXRob3V0IHVzaW5nIGEgZm9yIGxvb3AqKi4gVGhpcyBkb2Vzbid0IHdvcmsgd2VsbCB3aXRoIHVuaXRzLCBzbyBwcmlvciB0byBkb2luZyB0aGUgZml0LCByZW1vdmUgdGhlIHVuaXRzIG9mIHlvdXIgdGltZSBhbmQgZGlhbWV0ZXIgY29sdW1ucyB1c2luZyBgYXMudmVjdG9yKClgey5SfS4KCmBgYHtyIGluY2x1ZGU9cGFyYW1zJHNvbHV0aW9uLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9CnBhcnRpY2xlc19hdmUgJT4lIAogICAgbXV0YXRlKGRpYW0gICA9IGFzLnZlY3RvcihzZXRfdW5pdHMoZGlhbSwibm0iKSksCiAgICAgICAgICAgc2RkaWFtID0gYXMudmVjdG9yKHNldF91bml0cyhzZGRpYW0sIm5tIikpLAogICAgICAgICAgIHRpbWUgICA9IGFzLnZlY3Rvcih0aW1lKQogICAgICAgICAgICkgJT4lIAogICAgbmVzdChkYXRhPS1jKHN1Yl90aGljayxzdWJfYWdlLFQpKSAlPiUgCiAgICBtdXRhdGUoZml0ICAgID0gbWFwKGRhdGEsIH5sbShkYXRhPS4sIGRpYW1+dGltZSwgd2VpZ2h0cyA9IDEvc2RkaWFtKSksCiAgICAgICAgICAgdGlkaWVkID0gbWFwKGZpdCwgdGlkeSkpICU+JSAKICAgIHVubmVzdCh0aWRpZWQpICU+JSAKICAgIHNlbGVjdChzdWJfdGhpY2ssc3ViX2FnZSxULHRlcm0sZXN0aW1hdGUsc3RkLmVycm9yKSAlPiUgCiAgICBtdXRhdGUodGVybT1nc3ViKCJcXChJbnRlcmNlcHRcXCkiLCJ5MCIsdGVybSkpICU+JSAKICAgIG11dGF0ZSh0ZXJtPWdzdWIoInRpbWUiLCJzbG9wZSIsdGVybSkpICU+JSAKICAgIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB0ZXJtLCAKICAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSBjKGVzdGltYXRlLHN0ZC5lcnJvcikpICU+JSAKICAgIHNldF9uYW1lcyh+IHN0cl90b19sb3dlciguKSAlPiUKICAgICAgICAgICAgICAgIHN0cl9yZXBsYWNlX2FsbCgiZXN0aW1hdGVfIiwiIikgJT4lIAogICAgICAgICAgICAgICAgc3RyX3JlcGxhY2VfYWxsKCJzdGQuZXJyb3JfIiwiZCIpKSAlPiUgCiAgICBzZWxlY3Qoc3ViX3RoaWNrLHN1Yl9hZ2UsdCx5MCxkeTAsc2xvcGUsZHNsb3BlKQpgYGAKCiMjIERlbnNpdHkgYW5kIG9yZGVyaW5nIGFuYWx5c2lzCgotIE5vdyB3ZSB3YW50IHRvIHNlZSB0aGUgZXZvbHV0aW9uIG9mIHRoZSBkZW5zaXR5IG9mIHBhcnRpY2xlcyBhbmQgdGhlaXIgb3JkZXJpbmcuIE9uZSB3YXkgb2YgZG9pbmcgdGhpcyBpcyB0byBsb29rIGF0IHRoZSAqRyhyKSogZGlzdHJpYnV0aW9uLCAqaS5lLiogdGhlIHByb2JhYmlsaXR5IHRvIGZpbmQgYSBwYXJ0aWNsZSBpbiAqciogaWYgb25lIGlzIGluIDAuIEkgcHJvdmlkZSBoZXJlIGJlbG93IHRoZSBmdW5jdGlvbiBgZ29mcih4LHksZHIsUm1heClgey5SfSB0aGF0IGNvbXB1dGVzIGl0IGJldHdlZW4gYDBgIGFuZCBgUm1heGAgd2l0aCBhIHN0ZXAgYGRyYCwgcHJvdmlkZWQgdGhlICh4LHkpIHBvc2l0aW9ucyBvZiBwYXJ0aWNsZXMuCgpgYGB7ciBpbmNsdWRlPVRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZT1GQUxTRX0KZ29mciA8LSBmdW5jdGlvbih4LCB5LCBkcj0uMiwgUm1heD0xMCl7CiAgICAjIE1ha2Ugc3VyZSB1bml0cyBhcmUgdW5pZm9ybSBiZWZvcmUgdXNpbmcgZGlzdCgpCiAgICB1bml0cyh5KSA8LSB1bml0cyh4KSAKICAgICMgZHIgYW5kIFJtYXggYXJlIHVuaXRsZXNzIGJ1dCBzaG91bGQgYmUgZ2l2ZW4gaW4gdGhlIHNhbWUgdW5pdHMgYXMgeAogICAgZHIgICA8LSBhcy52ZWN0b3IoZHIpCiAgICBSbWF4IDwtIGFzLnZlY3RvcihSbWF4KQogICAgIyBHZXQgYSB2ZWN0b3Igb2YgYWxsIEV1Y2xpZGlhbiBkaXN0YW5jZXMKICAgIGRkICAgPC0gYXMudmVjdG9yKGRpc3QodGliYmxlOjp0aWJibGUoeCx5KSkpCiAgICAjIE1ha2UgYSBoaXN0b2dyYW0gb3V0IG9mIGl0CiAgICBkZC5oaXN0IDwtIGhpc3QoZGQsIAogICAgICAgICAgICAgICAgICAgIGJyZWFrcz1zZXEoMCwgbWF4KGRkKStkciwgYnk9ZHIpLAogICAgICAgICAgICAgICAgICAgIHBsb3Q9RkFMU0UpCiAgICAjIEdldCB0aGUgciB2YWx1ZXMKICAgIHIgPC0gZGQuaGlzdCRtaWRzCiAgICAjIENvbXB1dGUgdGhlIG5vcm1hbGl6YXRpb24gYnkgdGhlIHN1cmZhY2Ugb2YgdGhlIAogICAgIyByaW5nIG9mIHJhZGl1cyByIGFuZCB0aGlja25lc3MgZHIKICAgIHJsbyAgPC0gciAtIGRyLzIKICAgIHJ1cCAgPC0gciArIGRyLzIKICAgIHJpbmcgPC0gcGkqKHJ1cF4yIC0gcmxvXjIpCiAgICAjIFJldHVybiB0aGUgdGliYmxlIGNvbnRhaW5pbmcgciBhbmQgRyhyKSB3aXRoIHRoZSBzYW1lIHVuaXQgYXMgeAogICAgIyBPbmx5IGRhdGEgZm9yIHI8Um1heCBpcyB3YW50ZWQsIGFuZCB3ZSByZW1vdmUgdGhlIGZpcnN0IGVsZW1lbnQgdG9vCiAgICBkIDwtIHRpYmJsZTo6dGliYmxlKFIgICAgPSByW3I8Um1heF0sIAogICAgICAgICAgICAgICAgICAgICAgICBHb2ZSID0gZGQuaGlzdCRjb3VudHNbcjxSbWF4XS9yaW5nW3I8Um1heF0pICU+JSAKICAgICAgICAgICAgcmVuYW1lKHI9IlIiLGdvZnI9IkdvZlIiKQogICAgdW5pdHMoZCRyKSA8LSB1bml0cyh4KQogICAgZFstMSxdCn0KYGBgCgotIFVzaW5nIHBpcGUgb3BlcmF0aW9ucywgY29tcHV0ZSBHKHIpIGZvciBlYWNoIGltYWdlIGFuZCBzdG9yZSBpdCBpbnRvIGBwYXJ0aWNsZXNfZ29mcmAuIAogICAgLSBXZSB3YW50IHRvIGNvbXB1dGUgRyhyKSB1cCB0byA1MDAgbm0gYnkgc3RlcCBvZiAyIG5tLiBNYWtlIHN1cmUgeCwgeSwgZHIgYW5kIFJtYXggYXJlIGdpdmVuIHdpdGggdGhlIHNhbWUgdW5pdC4KICAgIC0gVGhlbiwgY29tcHV0ZSB0aGUgYXZlcmFnZSBHKHIpIGZvciBlYWNoIHNhbXBsZS4KICAgIC0gSm9pbiBgcGFydGljbGVzX2dvZnJgIHdpdGggYHNhbXBsZXNgIHRvIHJldHJpZXZlIHRoZSBzYW1wbGVzIGluZm9ybWF0aW9uCgpgYGB7ciBpbmNsdWRlPXBhcmFtcyRzb2x1dGlvbiwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFfQpwYXJ0aWNsZXNfZ29mciA8LSBwYXJ0aWNsZXMgJT4lIAogICAgbXV0YXRlKHggPSBzZXRfdW5pdHMoeCwibm0iKSwKICAgICAgICAgICB5ID0gc2V0X3VuaXRzKHksIm5tIikKICAgICAgICAgICApICU+JSAKICAgIG5lc3QoZGF0YSA9IC1jKHNhbXBsZSwgbnVtYmVyKSkgJT4lIAogICAgbXV0YXRlKEdvZlIgPSBtYXAoZGF0YSwgfmdvZnIoLiR4LCAuJHksIGRyPTIsIFJtYXg9NTAwKSkpICU+JSAKICAgIHVubmVzdChHb2ZSKSAlPiUgCiAgICBncm91cF9ieShzYW1wbGUsIHIpICU+JSAKICAgIHN1bW1hcml6ZShnb2ZyPW1lYW4oZ29mcikpICU+JSAKICAgIGlubmVyX2pvaW4oc2FtcGxlcykKYGBgCgotIEZpbmQgdGhlIGJlc3Qgd2F5IHRvIHJlcHJlc2VudCBHKHIpIGZvciBhbGwgc2FtcGxlcywgdGhhdCBhbGxvd3Mgc2VlaW5nIHRoZSBldm9sdXRpb24gd2l0aCBhbGwgcGFyYW1ldGVycy4KCmBgYHtyIGluY2x1ZGU9cGFyYW1zJHNvbHV0aW9uLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9CnBhcnRpY2xlc19nb2ZyICU+JSAKICAgIGdncGxvdChhZXMoeD1yLCAKICAgICAgICAgICAgICAgeT1nb2ZyLCAKICAgICAgICAgICAgICAgY29sb3I9ZmFjdG9yKHRpbWUpKSkrCiAgICAgICAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsb2VzcyIsIGFscGhhPS41LCBzcGFuPS4xNSwgc2U9RkFMU0UpKwogICAgICAgIGdlb21fbGluZShhbHBoYT0uMikrCiAgICAgICAgZXhwYW5kX2xpbWl0cyh4ID0gMCwgeT0wKSsKICAgICAgICBmYWNldF9ncmlkKHJlb3JkZXIocGFzdGUoVCwiSyIpLFQpfgogICAgICAgICAgICAgICAgICAgcmVvcmRlcihwYXN0ZShzdWJfdGhpY2ssIm5tIE5pIC0iLHN1Yl9hZ2UpLHN1Yl90aGljayksIAogICAgICAgICAgICAgICAgICAgc2NhbGVzPSJmcmVlX3kiKSsKICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikrCiAgICAgICAgbGFicyh4ICAgICA9ICJyIiwKICAgICAgICAgICAgIHkgICAgID0gIkcocikiLAogICAgICAgICAgICAgY29sb3IgPSAiVGltZSBbbWluXSIpCmBgYAoKCgoKCgoK